import logging.handlers
import sys
from os.path import join
import tqdm

logging.basicConfig(level=logging.INFO, format='[%(levelname)s %(filename)s %(funcName)s:%(lineno)d] %(message)s')

long_fmt = logging.Formatter(fmt='[%(levelname)s %(filename)s %(funcName)s:%(lineno)d] %(message)s', datefmt=None)
long_time_fmt = logging.Formatter(fmt='[%(asctime)s %(levelname)s %(filename)s %(funcName)s:%(lineno)d] %(message)s', datefmt=None)


class TqdmLoggingHandler(logging.Handler):
    def __init__(self, level=logging.NOTSET):
        super().__init__(level)

    def emit(self, record):
        try:
            msg = self.format(record)
            tqdm.tqdm.write(msg)
            self.flush()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)


# 标准输出（正常也就是打印到屏幕, 不会破坏tqdm进度条）
std_handler = TqdmLoggingHandler(logging.DEBUG)
std_handler.setFormatter(long_fmt)

cache = {}


class Logs:
    # 临时日志（只在屏幕上显示，不存储到文件）
    tmp = logging.getLogger('log_tmp')
    tmp.setLevel(logging.DEBUG)
    tmp.addHandler(std_handler)
    tmp.propagate = False

    def __init__(self, folder, level='INFO'):
        # brief 记录简要日志， 通常是统计分数等 (也会存储到all的日志文件里，时all的上下文更加完整）
        # all 记录细节日志， 全部存储到文件里，通常是训练过程中的细节，便于发现错误和debug
        # rotate 滚动细节日志， 滚动存储到文件里， 通常是部署服务后的日志，因为持续时间长，所以要滚动存储，避免占满硬盘
        if 'handler_brief' not in cache:
            cache['handler_brief'] = logging.FileHandler(join(folder, 'log_brief.log'), mode='w', encoding='utf8', delay=True)
            cache['handler_brief'].setLevel(level)
            cache['handler_brief'].setFormatter(long_fmt)
        if 'handler_all' not in cache:
            cache['handler_all'] = logging.FileHandler(join(folder, 'log_detail_all.log'), mode='w', encoding='utf8', delay=True)
            cache['handler_all'].setLevel(level)
            cache['handler_all'].setFormatter(long_time_fmt)
        if 'handler_rotate' not in cache:
            cache['handler_rotate'] = logging.handlers.RotatingFileHandler(join(folder, 'log_detail_rotate.log'),
                                                                           maxBytes=100000, backupCount=10, mode='w',
                                                                           encoding='utf8', delay=True)
            cache['handler_rotate'].setLevel(level)
            cache['handler_rotate'].setFormatter(long_time_fmt)

        if 'brief' not in cache:
            cache['brief'] = logging.getLogger('log_brief')
            cache['brief'].setLevel(level)
            cache['brief'].addHandler(std_handler)
            cache['brief'].addHandler(cache['handler_brief'])
            cache['brief'].addHandler(cache['handler_all'])
            cache['brief'].propagate = False
        self.brief = cache['brief']

        if 'all' not in cache:
            cache['all'] = logging.getLogger('log_all')
            cache['all'].setLevel(level)
            cache['all'].addHandler(std_handler)
            cache['all'].addHandler(cache['handler_all'])
            cache['all'].propagate = False
        self.all = cache['all']

        if 'rotate' not in cache:
            cache['rotate'] = logging.getLogger('log_rotate')
            cache['rotate'].setLevel(level)
            cache['rotate'].addHandler(std_handler)
            cache['rotate'].addHandler(cache['handler_rotate'])
            cache['rotate'].propagate = False
        self.rotate = cache['rotate']
